#pragma once

#include "Space.h"
#include "BoundedSpace.h"
#include "Vector.h"
#include "SpaceAgent.h"
#include <cmath>
#include "AdvancedDataLayer.h"
namespace org
{
	namespace spark
	{
		namespace data
		{


			//using org::spark::math::Function;
			//using org::spark::math::Matrix;
			using org::spark::space::BoundedSpace;
			using org::spark::space::Space;
			using org::spark::space::SpaceAgent;
			using org::spark::math::Vector;

			/*
			 * The basic implementation of the data layer interface
			 * Values are stored inside cells of a grid of the given dimension 
			 */
			class Grid : public AdvancedDataLayer
			{
			private:
				//static const long long serialVersionUID = -1581695024221018527LL;
				// Reference to the space object
			protected:
				Space *space;
				// Dimension of the grid
				int xSize, ySize;
				// Topology of the grid
				bool wrapX, wrapY;
				double xMin, xMax, yMin, yMax;

				// Auxiliary values for fast computations
				// The size of each rectangular grid cell
				double xStep, yStep;
				// The inverse of the grid cell size
				double invXStep, invYStep;

				// Data stored in the grid 
//ORIGINAL LINE: protected double[][] data;
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double **data;

//ORIGINAL LINE: protected double[][] readData;
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double **readData;
//ORIGINAL LINE: protected double[][] writeData;
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double **writeData;

				// Auxiliary array for some computations
			private:
//ORIGINAL LINE: private transient double[][] dataCopy;
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double **dataCopy;


			protected:
				



				/// <summary>
				/// Returns the data array. Use this method carefully
				/// @return
				/// </summary>
			public:
				virtual double **getData();


				virtual int getXSize();


				virtual int getYSize();

				Grid(Space *space0, int xSize, int ySize);
				/// <summary>
				/// Restricts the x coordinate in accordance with grid topology </summary>
				/// <param name="x">
				/// @return </param>
				virtual int restrictX(int x);

				/// <summary>
				/// Restricts the y coordinate in accordance with grid topology </summary>
				/// <param name="y">
				/// @return </param>
				virtual int restrictY(int y);

				/// <summary>
				/// Returns the grid x-coordinate corresponding to the space x-coordinate </summary>
				/// <param name="x">
				/// @return </param>
				virtual int findX(double x);

				/// <summary>
				/// Returns the grid y-coordinate corresponding to the space y-coordinate </summary>
				/// <param name="y">
				/// @return </param>
				virtual int findY(double y);

				/// <summary>
				/// Returns the coordinates of the grid cell </summary>
				/// <param name="x"> </param>
				/// <param name="y">
				/// @return </param>
				virtual Vector *getCenter(int x, int y);




				virtual double getXStep();


				virtual double getYStep();




				//************************************
				// DataLayer interface implementation
				//************************************


				virtual double getValue(Vector *p);


				virtual double addValue(Vector *p, double value);


				virtual void setValue(Vector *p, double value);


				virtual void setValue(double value);


				/// <summary>
				/// Returns a "smooth" gradient at the given point </summary>
				/// <param name="p">
				/// @return </param>
				virtual Vector *getSmoothGradient(Vector *p);


				virtual Vector *getGradient(Vector *p);

				/// <summary>
				/// Returns the uphill direction in the NetLogo sense </summary>
				/// <param name="p">
				/// @return </param>
				virtual Vector *getUphillDirection(Vector *p);


				virtual double addValue(SpaceAgent *agent, double value);


				virtual double getValue(SpaceAgent *agent);


				virtual void setValue(SpaceAgent *agent, double value);


				virtual double getTotalNumber();


				//virtual void setValue(double f);

				//************************************
				// AdvancedDataLayer interface implementation
				//************************************

				virtual void multiply(double value);


				virtual void add(double value);


				//virtual void convolution(Matrix *m);

				//Matrix *diffusion;
				virtual void diffuse2(double p);


				/// <summary>
				/// Diffusion with a mask.
				/// No diffusion to all cells with a positive mask value.
				/// </summary>
				virtual void diffuse(double p, Grid *mask);


				/// <summary>
				/// Diffusion operation
				/// </summary>
				virtual void diffuse(double p);



				/// <summary>
				/// Diffusion operation for the FF-topology
				/// </summary>
			protected:
				virtual void diffuseFF(double const p);


				/// <summary>
				/// Diffusion operation for the FT-topology
				/// </summary>
				virtual void diffuseFT(double const p);


				/// <summary>
				/// Diffusion operation for the TF-topology
				/// </summary>
				virtual void diffuseTF(double const p);



				/// <summary>
				/// Diffusion operation for the TT-topology
				/// </summary>
				virtual void diffuseTT(double const p);






				virtual void old_diffusion(double p);


			public:
				virtual double getTotalNumber(double xMin, double xMax, double yMin, double yMax);


				virtual double getTotalNumber(DataLayer *filter, double val);


				virtual void process(long long tick);


				virtual double getValue(int x, int y);


				virtual void setValue(int x, int y, double value);


				virtual void addValue(int x, int y, double value);


				virtual double getMax();


				virtual double getMin();


				virtual Space *getSpace();


				// FIXME: remove
				virtual void setSpace(Space *space);

				/// <summary>
				/// Custom deserialization is needed.
				/// </summary>
			private:
				//void readObject(ObjectInputStream *ois) //throw(IOException, ClassNotFoundException);

				/// <summary>
				/// Custom serialization is needed.
				/// </summary>
				//void writeObject(ObjectOutputStream *oos) //throw(IOException);



				/// <summary>
				/// Does nothing
				/// </summary>
			public:
				virtual void beginStep();


				/// <summary>
				/// Does nothing
				/// </summary>
				virtual void endStep();

			private:
				void InitializeInstanceFields();
			};

		}
	}


//----------------------------------------------------------------------------------------
//	
//	
//
//	This class provides the logic to simulate Java rectangular arrays, which are jagged
//	arrays with inner arrays of the same length.
//----------------------------------------------------------------------------------------
}